/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.ui.dialogs;

import java.util.HashSet;
import java.util.Iterator;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.Slot;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.utils.LookForElement;

/**
 * Dialog to choose an instance specification
 */
public class ChooseInstanceSpecificationDialog extends Dialog {
	
	/** classifier that should be in the list of classifiers for the choosen InstanceSpecification*/
	protected Classifier classifier;
	
	/** Selected Instance Specification*/
	protected InstanceSpecification selectedIS;

	/** slot for which the value will be an instance specification */
	protected Slot slot;

	/** reference top package (model, profile, etc.) of the slot */
	protected Package topPackage;
	
	/** The selection tree */
	protected Tree tree;
	
	/**
	 * Creates a enew ChooseInstanceSpecificationDialog 
	 * @param parent the parent Shell for this dialog
	 * @param classifier the classifier for which to choose instanceSpecification
	 * @param topPackage the slot for which a value is searched
	 */
	public ChooseInstanceSpecificationDialog (Shell parent, Classifier classifier, Slot slot) {
		super(parent);
		this.slot = slot;
		this.topPackage = LookForElement.topPackage(slot);
		this.classifier = classifier;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
	 */
	@Override
	protected void configureShell(Shell shell) {
		super.configureShell(shell);
		shell.setText("Choose an Instance Specification");
	}

	/* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
	protected Control createDialogArea(Composite parent){
		Composite composite = (Composite)super.createDialogArea(parent);
		tree = new Tree(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);

		TreeItem item = new TreeItem(tree, SWT.NONE);
		item.setText(PapyrusPlugin.UML_LABEL_PROVIDER.getText(topPackage, true));
		item.setData(topPackage);
		item.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(topPackage));
		buildImportTreeList(item, topPackage);

		// build basic imported packages list
		HashSet<Package> importedPackages = LookForElement.buildImportedTopPackagesList(topPackage, new HashSet<Package>());
		
		// extends this list to all imported packages  (import from import, etc...)
		Iterator<Package> packages = LookForElement.buildExtendedImportedPackagesList(importedPackages, topPackage).iterator();

		while (packages.hasNext()) {
			Package currentPackage = (Package) packages.next();
			item = new TreeItem(tree, SWT.NONE);
			item.setText(PapyrusPlugin.UML_LABEL_PROVIDER.getText(currentPackage, true));
			item.setData(currentPackage);
			item.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(currentPackage));
			buildImportTreeList(item, currentPackage);
		}
		tree.setLayoutData(new GridData(300, 300));

		tree.addSelectionListener(new SelectionListener() {
			public void widgetSelected(SelectionEvent e){
				setSelection(e);
			}

			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		return composite;
	}
	
	/**
	 * Sets the selection, i.e. the element that will be returned by the dialog.
	 * @param e the selection event
	 */
	protected void setSelection(SelectionEvent e) {
		Widget selectedWidget = e.item;
		if(selectedWidget.getData() instanceof InstanceSpecification) {
			selectedIS = (InstanceSpecification)selectedWidget.getData();
		} else {
			// sets association to null, if selected element is not an type.
			// erase a previous selected type
			// example: select type T1, then a package
			// if association is not set to null, it keeps the type T1 as result
			// whereas the package is selected
			// TODO should improve the dialog: Ok should not be enabled when type is null
			// TODO should improve the dialog: selection should be initialized depending on 
			// the original type( ex open  a window on an already typed element)
			selectedIS = null;
		}
	}

	
	/**
	 * This method builds the element tree widget containing all packageable elements of a given package.
	 * @param _package the package to explore
	 * @param elemTree tree parent of packageable elements
	 */
	protected void buildImportTreeList(TreeItem elemTree, Package _package){
		Iterator<PackageableElement> elemIter = _package.getPackagedElements().iterator();
		while(elemIter.hasNext()) {
			Element elem = (Element) elemIter.next();
			if(elem instanceof Package){
				TreeItem item = new TreeItem(elemTree, SWT.NONE);
				item.setText(PapyrusPlugin.UML_LABEL_PROVIDER.getText(elem, true));
				item.setData(elem);
				item.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(elem));
				buildImportTreeList(item, (Package)elem);
			}
			else if(elem instanceof InstanceSpecification){
				if(((InstanceSpecification)elem).getClassifiers().contains(classifier)){
					TreeItem item = new TreeItem(elemTree, SWT.NONE);
					item.setText(PapyrusPlugin.UML_LABEL_PROVIDER.getText(elem, true));
					item.setData(elem);
					item.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(elem));
				}
			} 
		}
	}
	
	/**
	 * Returns the selected Instance specification.
	 * @return the selected Instance specification, or <code>null</code> if none was choosen 
	 */
	public InstanceSpecification getResult(){
		return selectedIS;
	}
}
